/*
 * \brief  Pistachio-specific implementation of the IO_MEM session interface
 * \author Julian Stecklina
 * \date   2008-04-09
 *
 */

/*
 * Copyright (C) 2008-2009 Julian Stecklina
 * Genode Labs, Feske & Helmuth Systementwicklung GbR
 *
 * This file is part of the Genode OS framework, which is distributed
 * under the terms of the GNU General Public License version 2.
 */

#include <pistachio/kip.h>
#include "platform.h"
#include "util.h"
#include "io_mem_session_component.h"

namespace Pistachio {
#include <l4/ipc.h>
#include <l4/sigma0.h>
}

using namespace Genode;


/*
 * TODO This should take a size parameter and check if the whole
 *      region is "normal" memory.
 */
bool is_conventional_memory(addr_t base)
{
	using namespace Pistachio;
	void *kip = get_kip();

	/* I miss useful programming languages... */
	for (L4_Word_t i = 0; i < L4_NumMemoryDescriptors(kip); i++) {
		L4_MemoryDesc_t *d = L4_MemoryDesc(kip, i);

		if (!L4_IsVirtual(d) && (L4_Type(d) == 1))
			if ((L4_Low(d) <= base) && (base <= L4_High(d)))
				return true;
	}

	return false;
}


void Io_mem_session_component::_unmap_local(addr_t base, size_t size)
{
	/* TODO .... */
	PERR("not yet implemented!");
}


addr_t Io_mem_session_component::_map_local(addr_t base, size_t size)
{
	using namespace Pistachio;

	PDBG("base = 0x%08lx, size = 0x%08x", base, size);

	addr_t local_base;
	size_t page_size = get_page_size();

	/* special case for the null page */
	if (is_conventional_memory(base))
		local_base = base;

	else {

		/* find appropriate region for mapping */
		void *result = 0;
		platform()->region_alloc()->alloc_aligned(size, &result, get_page_size_log2());
		local_base = (addr_t)result;

		if (!local_base)
			PERR("alloc_aligned failed!");
	}

	for (unsigned off = 0; size; size -= page_size, off += page_size) {

		L4_Fpage_t ret = L4_Sigma0_GetPage(get_sigma0(),
		                                   L4_Fpage(base + off, page_size),
		                                   L4_Fpage(local_base + off, page_size));

		if (L4_IsNilFpage(ret))
			PERR("Got nil fpage for 0x%08lx. (ignoring)", base + off);
	}

	return local_base;
}
